package com.nlelpct.security.filter;

import com.alibaba.fastjson2.JSON;
import com.nlelpct.constant.MySecurityConstant;
import com.nlelpct.constant.SystemConstant;
import com.nlelpct.enums.ResponseEnum;
import com.nlelpct.model.vo.ResponseResult;
import com.nlelpct.security.context.ThreadParameter;
import com.nlelpct.security.model.MyUser;
import com.nlelpct.security.utils.ResponseUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.ObjectUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * @author :小马
 * @date : 2023-07-12
 */
@Slf4j
public class AccreditFilter extends OncePerRequestFilter {
    private final RedisTemplate<String, Object> redisTemplate;

    public AccreditFilter(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 权限相关的操作
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) {
        String token = request.getHeader(MySecurityConstant.SECURITY_TOKEN);
        if (ObjectUtils.isEmpty(token)) {
            ResponseUtil.out(response, ResponseResult.error(ResponseEnum.TOKEN_NOT_FIND_ENUM));
            return;
        }
        try {
            String tokenString = redisTemplate.opsForValue().get(token).toString();
            MyUser myUser = JSON.parseObject(tokenString, MyUser.class);
            HashMap<String, String> localMap = new HashMap<>();
            localMap.put(SystemConstant.COMPANY_ID, Optional.ofNullable(request.getHeader(SystemConstant.COMPANY_ID)).orElse(""));
            ThreadParameter.setLocalMap(localMap);
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                    new UsernamePasswordAuthenticationToken(myUser, token, myUser.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            setLocalThreadParameter(request);
            redisTemplate.opsForValue().set(token, JSON.toJSONString(myUser), MySecurityConstant.TOKEN_TIME, TimeUnit.MINUTES);
            redisTemplate.opsForValue().set(myUser.getUserId(), token, MySecurityConstant.TOKEN_TIME, TimeUnit.MINUTES);
        } catch (Exception e) {
            log.error("校验token出现异常,异常信息如下: ");
            e.printStackTrace();
            ResponseUtil.out(response, ResponseResult.error(ResponseEnum.TOKEN_EXPIRED_ENUM));
            return;
        }
        try {
            filterChain.doFilter(request, response);
        } catch (Exception e) {
            e.printStackTrace();
            ResponseUtil.out(response, ResponseResult.error(ResponseEnum.ORDINARY_FAIL_ENUM));
        }
    }


    private void setLocalThreadParameter(HttpServletRequest request) {
        HashMap<String, String> paramMap = new HashMap<>();
        paramMap.put(SystemConstant.TERMINAL_INFO, Optional.ofNullable(request.getHeader(SystemConstant.TERMINAL_INFO)).orElse(""));
        paramMap.put(SystemConstant.COMPANY_ID, Optional.ofNullable(request.getHeader(SystemConstant.COMPANY_ID)).orElse(""));
        paramMap.put(SystemConstant.SYSTEM_ID, Optional.ofNullable(request.getHeader(SystemConstant.SYSTEM_ID)).orElse(""));
        paramMap.put(SystemConstant.EMPLOYEE_ID, Optional.ofNullable(request.getHeader(SystemConstant.EMPLOYEE_ID)).orElse(""));
        paramMap.put(SystemConstant.MODULE, Optional.ofNullable(request.getHeader(SystemConstant.MODULE)).orElse(""));
        paramMap.put(SystemConstant.PAGE, Optional.ofNullable(request.getHeader(SystemConstant.PAGE)).orElse(""));
        paramMap.put(SystemConstant.LOG_BASE_INFO_REDIS_KEY, Optional.ofNullable(request.getHeader(SystemConstant.LOG_BASE_INFO_REDIS_KEY)).orElse(""));
        ThreadParameter.setLocalMap(paramMap);
    }
}
